<?php
namespace app\process;

use Workerman\Worker;
use Workerman\Crontab\Crontab;
use app\model\BizModel;
use app\model\BizPayRecordModel;
use app\model\BizGoodsTicketModel;
use app\model\BillModel;
use support\Db;

class DoBill
{
	public function onWorkerStart(Worker $worker)
	{
		// 每月1日凌晨1点执行结算
		new Crontab('*/2 * * * *', function () use ($worker) {
			$this->processMonthlyBilling();
		});
	}

	/**
	 * 处理每月结算
	 */
	private function processMonthlyBilling()
	{
		try {
			echo "开始执行每月结算任务: " . date('Y-m-d H:i:s') . "\n";
			
			// 获取上月份
			$billMonth = date('Y-m', strtotime('first day of last month'));
			
			// 查询所有商家
			$bizList = BizModel::where(function($query) use ($billMonth) {
				$query->where('recent_bill_date', '<>', $billMonth)
					  ->orWhereNull('recent_bill_date');
			})->get();
			
			foreach ($bizList as $biz) {
				$this->processBizBilling($biz, $billMonth);
			}
			
			echo "每月结算任务完成: " . date('Y-m-d H:i:s') . "\n";
			
		} catch (\Exception $e) {
			echo "每月结算任务异常: " . $e->getMessage() . "\n";
		}
	}

	/**
	 * 处理单个商家的结算
	 * @param BizModel $biz 商家信息
	 * @param string $currentMonth 当前月份
	 */
	private function processBizBilling($biz, $billMonth)
	{
		try {
			echo "处理商家 {$biz->id} ({$biz->name}) 的结算\n";
			
			// 检查是否已经结算过当前月份
			if ($biz->recent_bill_date === $billMonth) {
				echo "商家 {$biz->id} 已结算过 {$billMonth}，跳过\n";
				return;
			}
			
			// 统计未结算的随心付记录
			$payRecords = $this->getUnbilledPayRecords($biz->id,$billMonth);
			$payRecordsTotal = $this->calculatePayRecordsTotal($payRecords,$biz->pay_record_settlement_discount);
			
			// 统计未结算的核销码
			$tickets = $this->getUnbilledTickets($biz->id);
			$ticketsTotal = $this->calculateTicketsTotal($tickets);
			
			// 计算总金额
			$totalAmount = $payRecordsTotal + $ticketsTotal;
			
			echo "商家 {$biz->id} 未结算金额: 随心付 {$payRecordsTotal} + 核销码 {$ticketsTotal} = {$totalAmount}\n";
			
			// 如果有需要结算的金额，创建结算单
			if ($totalAmount > 0) {
                echo "创建结算单\n";
				$this->createBill($biz, $billMonth, $totalAmount, $payRecords, $tickets);
			} else {
				// 即使没有金额，也要更新最近结算时间
				$biz->recent_bill_date = $billMonth;
				$biz->save();
				echo "商家 {$biz->id} 无结算金额，仅更新结算时间\n";
			}
			
		} catch (\Exception $e) {
			echo "处理商家 {$biz->id} 结算异常: " . $e->getMessage() . "\n";
		}
	}

	/**
	 * 获取未结算的随心付记录
	 * @param int $bizId 商家ID
	 * @return array
	 */
	private function getUnbilledPayRecords($bizId,$billMonth)
	{
		return BizPayRecordModel::where('biz_id', $bizId)
			->where('pay_status', '=',1) // 已支付
            ->where('refund_status','=',0)
			->where('bill_id', 0) // 未结算
            // ->where('paid_at', '<=', strtotime(date('Y-m-t 23:59:59', strtotime($billMonth.'-01'))))
			->get()
			->toArray();
	}

	/**
	 * 获取未结算的核销码
	 * @param int $bizId 商家ID
	 * @return array
	 */
	private function getUnbilledTickets($bizId)
	{
		return BizGoodsTicketModel::where('biz_id', $bizId)
			->where('status', 1) // 已使用
            ->where('refund_record_id','=',0)
			->where('bill_id', 0) // 未结算
            ->where('created_at','<',strtotime(date('Y-m-01 00:00:00')))
			->get()
			->toArray();

	}

	/**
	 * 计算随心付记录总金额
	 * @param array $payRecords 随心付记录
     * @param float $discount 结算折扣
	 * @return float
	 */
	private function calculatePayRecordsTotal($payRecords,$discount)
	{
		$total = 0;
		foreach ($payRecords as $record) {
			$total += $record['pay_price'] * round(($discount/100),2);
		}
		return round($total, 2);
	}

	/**
	 * 计算核销码总金额
	 * @param array $tickets 核销码记录
	 * @return float
	 */
	private function calculateTicketsTotal($tickets)
	{
		$total = 0;
		foreach ($tickets as $ticket) {
			// 根据业务逻辑计算商家应得金额
			// 这里假设商家获得核销码金额的70%（可根据实际业务调整）
			$total += $ticket['money'] * 0.7;
		}
		return round($total, 2);
	}

	/**
	 * 创建结算单
	 * @param BizModel $biz 商家信息
	 * @param string $currentMonth 当前月份
	 * @param float $totalAmount 总金额
	 * @param array $payRecords 随心付记录
	 * @param array $tickets 核销码记录
	 */
	private function createBill($biz, $currentMonth, $totalAmount, $payRecords, $tickets)
	{
		// 开启事务
		Db::beginTransaction();
		
		try {
			// 创建结算单
			$bill = new BillModel();
			$bill->biz_id = $biz->id;
			$bill->money = $totalAmount;
			$bill->day = $currentMonth;
			$bill->status = 'uncheck'; // 未审核
			$bill->created_at = time();
			$bill->updated_at = time();
			$bill->save();
			
			$billId = $bill->id;
			echo "创建结算单: ID={$billId}, 金额={$totalAmount}\n";
			
			// 更新随心付记录的bill_id（分批处理）
			if (!empty($payRecords)) {
				$payRecordIds = array_column($payRecords, 'id');
				$this->batchUpdatePayRecords($payRecordIds, $billId);
				echo "更新随心付记录数量: " . count($payRecordIds) . "\n";
			}
			
			// 更新核销码记录的bill_id（分批处理）
			if (!empty($tickets)) {
				$ticketIds = array_column($tickets, 'id');
				$this->batchUpdateTickets($ticketIds, $billId);
				echo "更新核销码记录数量: " . count($ticketIds) . "\n";
			}
			
			// 更新商家最近结算时间
			$biz->recent_bill_date = $currentMonth;
			$biz->save();
			
			// 提交事务
			Db::commit();
			
			echo "商家 {$biz->id} 结算完成，结算单ID: {$billId}\n";
			
		} catch (\Exception $e) {
			// 回滚事务
			Db::rollback();
			throw $e;
		}
	}

	/**
	 * 分批更新随心付记录
	 * @param array $ids 记录ID数组
	 * @param int $billId 结算单ID
	 */
	private function batchUpdatePayRecords($ids, $billId)
	{
		$batchSize = 1000; // 每批处理1000条记录
		$chunks = array_chunk($ids, $batchSize);
		$totalBatches = count($chunks);
		
		echo "开始分批更新随心付记录，共 {$totalBatches} 批\n";
		
		foreach ($chunks as $index => $chunk) {
			$startTime = microtime(true);
			
			BizPayRecordModel::whereIn('id', $chunk)
				->update(['bill_id' => $billId]);
			
			$endTime = microtime(true);
			$duration = round(($endTime - $startTime) * 1000, 2); // 毫秒
			
			echo "第 " . ($index + 1) . "/{$totalBatches} 批完成，处理 " . count($chunk) . " 条记录，耗时 {$duration}ms\n";
		}
	}

	/**
	 * 分批更新核销码记录
	 * @param array $ids 记录ID数组
	 * @param int $billId 结算单ID
	 */
	private function batchUpdateTickets($ids, $billId)
	{
		$batchSize = 1000; // 每批处理1000条记录
		$chunks = array_chunk($ids, $batchSize);
		$totalBatches = count($chunks);
		
		echo "开始分批更新核销码记录，共 {$totalBatches} 批\n";
		
		foreach ($chunks as $index => $chunk) {
			$startTime = microtime(true);
			
			BizGoodsTicketModel::whereIn('id', $chunk)
				->update(['bill_id' => $billId]);
			
			$endTime = microtime(true);
			$duration = round(($endTime - $startTime) * 1000, 2); // 毫秒
			
			echo "第 " . ($index + 1) . "/{$totalBatches} 批完成，处理 " . count($chunk) . " 条记录，耗时 {$duration}ms\n";
		}
	}
}
